using System.Collections.Generic;
using System;
using Cysharp.Threading.Tasks;
using Unity.VisualScripting;
using UnityEngine;
namespace MiniAnimation
{
    interface ISequenceFactory
    {
        SequenceNode CreateSequenceNode(UniTaskFunc func);
        SequenceNode CreateSequenceNode(Action action);
        SequenceNode CreateSequenceNode(float internalTime);
        void Recycle(SequenceNode node);
    }
    public partial class MiniAnimate
    {
        public static MiniSequence Sequence()
        {
            return new MiniSequence();
        }

        public class MiniSequence : ISequenceFactory
        {
            LoopingQueue<SequenceNode> nodesQueue;
            public event System.Action OnCompleted;
            UniTaskCompletionSource<bool> tcs;
            public UniTask<bool> Task => tcs.Task;
            public MiniSequence()
            {
                tcs= new UniTaskCompletionSource<bool>();
                nodesQueue = new LoopingQueue<SequenceNode>();
            }
            #region  add
            public void Join(MiniAnim miniAnim)
            {
                miniAnim.Pause();
                var node = nodesQueue.Tail();
                if (node == default(SequenceNode))
                {
                    nodesQueue.Enqueue(miniAnim);
                }
                else
                {
                    nodesQueue.Tail().AddSubChildren(miniAnim);
                }
            }
            public void Append(MiniAnim miniAnim)
            {
                miniAnim.Pause();
                nodesQueue.Enqueue(miniAnim);
            }
            public void AppendUnitaskFunc(UniTaskFunc func)
            {

                var seq = CreateSequenceNode(func);
                seq.Pause();
                nodesQueue.Enqueue(seq);
            }
            public void AppendTaskFunc(TaskFunc func)
            {
                var seq = CreateSequenceNode(func);
                seq.Pause();
                nodesQueue.Enqueue(seq);
            }
            public void AppendInternal(float Internal)
            {
                var seq = CreateSequenceNode(Internal);
                seq.Pause();
                nodesQueue.Enqueue(seq);
            }
            public void AppendAction(Action action)
            {
                var seq = CreateSequenceNode(action);
                seq.Pause();
                nodesQueue.Enqueue(seq);
            }
            #endregion
            public void Excute()
            {
                ExcuteNext();
            }
            private async void ExcuteNext()
            {
                if (nodesQueue.Count == 0)
                {
                    OnCompleted?.Invoke();
                    tcs.TrySetResult(true);
                    return;
                }
                var node = nodesQueue.Peek();
                try
                {
                    await node.Excute();
                }
                catch (System.Exception e)
                {
                    Debug.LogWarning("sequence node eccute error:" + e.Message);
                }
                //说明被kill了
                if (nodesQueue.Count ==0){
                    return;
                }
                nodesQueue.Dequeue();
                if (!isKilled)
                {
                    ExcuteNext();
                }
            }
            bool isKilled = false;
            public void Kill()
            {
                isKilled = true;
                tcs.TrySetResult(false);
                while (nodesQueue.Count > 0){
                    nodesQueue.Dequeue().Kill();
                }
                nodesQueue.Clear();
            }
            public SequenceNode CreateSequenceNode(UniTaskFunc func)
            {
                return new UnitaskFuncNode(func);
            }
            public SequenceNode CreateSequenceNode(TaskFunc func)
            {
                return new TaskFuncNode(func);
            }
            public SequenceNode CreateSequenceNode(Action action)
            {
                return new ActionNode(action);
            }
            public SequenceNode CreateSequenceNode(float internalTime)
            {
                return new IntervalNode(internalTime);
            }
            public void Recycle(SequenceNode node)
            {
            }
        }
    }
}